﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace BlackStar
{
    public delegate void ClipboardSet(string value);
    public delegate string ClipboardRequest();

    public class Clipboard
    {
        // This class is probably more complicated than it should have been.
        // To avoid giving blackstar a dependancy on System.Windows.Forms, 
        // this class was created. It emulates a text clipboard so that on the 
        // XBox and Zune it can work as an internal clipboard. However on windows
        // the application using this library can set event handlers to TextSet and 
        // TextGet that tie the code to the actual windows Clipboard. 
        //
        // This is where the trouble comes in. Normal windows application automatically get
        // their ThreadApartmentState to STA, but in an XNA application the default template 
        // does not do that. So we can either force the client application to 
        // use and STA thread, or we can spawn our own threads as needed. 
        //
        // Basically whenever we need to raise one of the events, we create a new thread
        // that is STA, start it and join. The STAWorker object is used to pass the text value 
        // between the main thread and child threads.
        //
        // The end result is that the client application can simply assing event 
        // handlers and not worry about its thread apartment state.

        private STAWorker worker = new STAWorker();

        public event ClipboardSet TextSet
        {
            add { worker.TextSet += value; }
            remove { worker.TextSet -= value; }
        }

        public event ClipboardRequest TextGet
        {
            add { worker.TextGet += value; }
            remove { worker.TextGet -= value; }
        }

        class STAWorker
        {
            public event ClipboardSet TextSet;
            public event ClipboardRequest TextGet;

            public string Text = string.Empty;

            public void DoGet()
            { if (TextGet != null) Text = TextGet(); }

            public void DoSet()
            { if (TextSet != null) TextSet(Text); }
        }

        public string Text
        {
            get
            {
                Thread workerThread = new Thread(new ThreadStart(worker.DoGet));
                workerThread.SetApartmentState(ApartmentState.STA);
                workerThread.Start();
                workerThread.Join();
                return worker.Text;
            }
            set
            {
                worker.Text = value;
                Thread workerThread = new Thread(new ThreadStart(worker.DoSet));
                workerThread.SetApartmentState( ApartmentState.STA);
                workerThread.Start();
                workerThread.Join();
            }
        }
    }
}
